package com.umeox.ota.mvvm.viewModel;

import android.app.Application;
import android.os.Handler;
import android.os.Looper;
import android.widget.Toast;

import androidx.lifecycle.MutableLiveData;

import com.abupdate.fotainject.FotaInject;
import com.abupdate.fotainject.FotaInjector;
import com.abupdate.iot_libs.OtaAgentPolicy;
import com.abupdate.iot_libs.data.constant.Error;
import com.abupdate.iot_libs.data.local.DeviceInfo;
import com.abupdate.iot_libs.data.local.OtaEntity;
import com.abupdate.iot_libs.data.remote.VersionInfo;
import com.abupdate.iot_libs.engine.otaStatus.OtaStatus;
import com.abupdate.iot_libs.engine.otaStatus.OtaStatusMgr;
import com.abupdate.iot_libs.engine.policy.PolicyManager;
import com.abupdate.iot_libs.engine.thread.Dispatcher;
import com.abupdate.iot_libs.engine.thread.NamedRunnable;
import com.abupdate.iot_libs.interact.callback.IRebootUpgradeCallBack;
import com.abupdate.iot_libs.interact.task.UpdateTask;
import com.abupdate.iot_libs.utils.NetUtils;
import com.abupdate.iot_libs.utils.SPFTool;
import com.abupdate.sdk_annotation.Inject;
import com.abupdate.trace.Trace;
import com.umeox.ota.R;
import com.umeox.ota.data.constant.Constant;
import com.umeox.ota.data.constant.LocalOtaStatus;
import com.umeox.ota.engine.FotaInitTask;
import com.umeox.ota.gloable.App;
import com.umeox.ota.interact.callback.ICheckVersionInter;
import com.umeox.ota.interact.callback.IDownloadInter;
import com.umeox.ota.interact.callback.IOtaOperationFailedInter;
import com.umeox.ota.mvvm.BaseViewModel;
import com.umeox.ota.mvvm.model.MainModel;
import com.umeox.ota.ui.activity.MainActivity;
import com.umeox.ota.utils.ActivityCollector;
import com.umeox.ota.utils.CleanUtils;
import com.umeox.ota.utils.RxTime;
import com.umeox.ota.utils.UnitProvide;

import java.io.File;

/**
 * @author fighter_lee
 * @date 2018/7/19
 */
public class HomeViewModel extends BaseViewModel<MainModel> {
    private static final String TAG = "MainViewModel";

    private FotaInject fotaInject;

    private IOtaOperationFailedInter iOtaOperationFailedInter;


    public final MutableLiveData<String> versionName = new MutableLiveData<>();
    public final MutableLiveData<String> progressObservable = new MutableLiveData<>();
    public final MutableLiveData<Integer> dlProgress = new MutableLiveData<>();


    public final MutableLiveData<OtaStatus> otaStatusMutableLiveData = new MutableLiveData<>();
    public final MutableLiveData<LocalOtaStatus> localOtaStatusMutableLiveData = new MutableLiveData<>();
    public final MutableLiveData<Boolean> contentVisibility = new MutableLiveData<>();

    public final MutableLiveData<VersionInfo> displayNewVersionInfo = new MutableLiveData<>();

    /**
     * 是否本地升级标志位
     */
    public static final String SP_IS_LOCAL_UPDATE = "sp_is_local_update";

    /**
     * 本地升级文件是否拷贝中
     */
    public static final String SP_IS_COPY_FILE = "sp_is_copy_file";

    @Inject
    public OtaEntity otaEntity;

    @Inject
    public PolicyManager policyManager;

    @Inject
    public VersionInfo versionInfo;

    @Inject
    public DeviceInfo deviceInfo;
    private Handler handler = new Handler(Looper.getMainLooper());

    public HomeViewModel(Application context, MainModel model) {
        super(context, model);
    }

    public boolean fotaInitCompleted() {
        boolean completed = FotaInitTask.isCompleted();
        if (completed) {
            fotaInject = FotaInjector.inject(this);
            registerListener();
        }
        return completed;
    }

    public void initData() {
        OtaStatus otaStatus = mModel.getState();
        initData(otaStatus == OtaStatus.CHECKING ? OtaStatus.IDLE : otaStatus);
    }

    public void initData(OtaStatus status) {
        Trace.d(TAG, "current state: " + status.name()+" Thread.currentThread:"+Thread.currentThread().getName());
        otaStatusMutableLiveData.postValue(status == null ? OtaStatus.IDLE : status);
        if (status == OtaStatus.IDLE || status == OtaStatus.CHECKING) {

            versionName.postValue(deviceInfo.version);
        } else {
            if (versionInfo != null) {
                displayNewVersionInfo.postValue(versionInfo);
                versionName.postValue(versionInfo.versionAlias);
            } else {
                Trace.d(TAG, "versionInfo is null ");
            }
        }
    }

    public void checkVersion() {
        otaStatusMutableLiveData.postValue(OtaStatus.CHECKING);
        if (!NetUtils.isNetWorkAvailable()) {
            otaStatusMutableLiveData.postValue(OtaStatus.IDLE);
            iCheckVersionInter.onFailed(OtaAgentPolicy.sCx.getString(R.string.net_error_tips));
            return;
        }
        mModel.checkVersionTask(iCheckVersionInter);
    }

    public void cancelDownload() {
        Dispatcher.getDispatcher().enqueue(new NamedRunnable("download cancel") {
            @Override
            protected void execute() {
                if (mModel.downloadCancel()) {
                    otaStatusMutableLiveData.postValue(OtaStatus.DOWNLOAD_PAUSE);
                }
            }
        });
    }

    public void localUpgrade(final String localFilePath) {
        if (!new File(localFilePath).exists()) {
            otaStatusMutableLiveData.postValue(OtaStatus.IDLE);
            iLocalRebootUpgradeCallBack.onError(Error.UPGRADE_FILE_NOT_EXIST);
            return;
        }
        long internalAvailableSpace = UnitProvide.getInstance().getStorageSpace(localFilePath);
        double needSpace = (new File(localFilePath).length() * 1.5f);
        Trace.d(TAG, "internalAvailableSpace: " + internalAvailableSpace + ", needSpace: " + needSpace);
        if (internalAvailableSpace < needSpace) {
            //本地升级时，剩余空间小于升级包的 1.5 倍时提示失败
            localOtaStatusMutableLiveData.postValue(LocalOtaStatus.UPGRADE_FAILED);
            iLocalRebootUpgradeCallBack.onError(Error.DOWNLOADING_MEMORY_NOT_ENOUGH);
            return;
        }
        mModel.registerUpgradeListener(iLocalRebootUpgradeCallBack);
        //本地升级时重置 ota 状态为 idle
        UpdateTask.getInstance().setAllUpdateFinish();
        SPFTool.putBoolean(SP_IS_LOCAL_UPDATE, true);
        SPFTool.putBoolean(SP_IS_COPY_FILE, true);
        otaStatusMutableLiveData.postValue(OtaStatus.UPGRADING);
        localOtaStatusMutableLiveData.postValue(LocalOtaStatus.UPGRADING);
        dlProgress.postValue(1);
        mModel.localRebootUpgrade(localFilePath, iLocalRebootUpgradeCallBack);
    }

    public void upgrade() {
        if (!new File(otaEntity.getFilePath()).exists()) {
            Trace.d(TAG, "upgrade() file not exists");
            OtaStatusMgr.getInstance().refreshOtaStatus(OtaStatus.IDLE);
            iRebootUpgradeCallBack.onError(Error.UPGRADE_FILE_NOT_EXIST);
            return;
        }

        long internalAvailableSpace = UnitProvide.getInstance().getStorageSpace(otaEntity.getFilePath());
        double needSpace = (new File(otaEntity.getFilePath()).length() * 1.5f);
        Trace.d(TAG, "internal available space: " + internalAvailableSpace + ", needSpace: " + needSpace);
        if (internalAvailableSpace < needSpace) {
            //ota 升级时，剩余空间小于升级包的 1.5 倍时提示失败
            otaStatusMutableLiveData.postValue(OtaStatus.UPGRADE_FAIL);
            iRebootUpgradeCallBack.onError(Error.DOWNLOADING_MEMORY_NOT_ENOUGH);
            return;
        }
        otaStatusMutableLiveData.postValue(OtaStatus.UPGRADING);
        localOtaStatusMutableLiveData.postValue(null);
        dlProgress.postValue(1);
        mModel.registerUpgradeListener(iRebootUpgradeCallBack);
        mModel.rebootUpgrade(iRebootUpgradeCallBack);
    }

    public void download(boolean useMobileNetwork) {
        String networkState = NetUtils.getNetworkState(App.sCx);
        if (!NetUtils.isNetWorkAvailable()) {
            otaStatusMutableLiveData.postValue(OtaStatus.DOWNLOADING);
            iOtaOperationFailedInter.downloadFailed(Constant.getDlTipByErrorCode(99));
            otaStatusMutableLiveData.postValue(OtaStatus.DOWNLOAD_FAILED);
            return;
        }
        boolean notSatisfiedWifiCondition = (policyManager.isRequestWifi() && !NetUtils.NETWORK_WIFI.equals(networkState))&&!useMobileNetwork;
        Trace.d(TAG, "download() not satisfied wifi condition: %s", notSatisfiedWifiCondition);
        if (notSatisfiedWifiCondition) {
            otaStatusMutableLiveData.postValue(OtaStatus.DOWNLOADING);
            iOtaOperationFailedInter.downloadFailed(getApplication().getString(R.string.download_mobile_network));
            otaStatusMutableLiveData.postValue(OtaStatus.DOWNLOAD_FAILED);
            return;
        }
        //空间判断
        if (!policyManager.isStorageSpaceEnough(otaEntity.getFilePath())) {
            Trace.d(TAG, "memory not enough ");
            otaStatusMutableLiveData.postValue(OtaStatus.DOWNLOADING);
            iOtaOperationFailedInter.downloadFailed(getApplication().getString(R.string.tips_download_memory_not_enough));
            otaStatusMutableLiveData.postValue(OtaStatus.DOWNLOAD_FAILED);
            return;
        }

        otaStatusMutableLiveData.postValue(OtaStatus.DOWNLOADING);
        dlProgress.postValue(1);
        mModel.download(iDownloadInter);
    }

    public void setCallback(IOtaOperationFailedInter iOtaOperationFailedInter) {
        this.iOtaOperationFailedInter = iOtaOperationFailedInter;
    }

    ICheckVersionInter iCheckVersionInter = new ICheckVersionInter() {
        @Override
        public void onCheckSuccess(VersionInfo versionInfo) {
            otaStatusMutableLiveData.postValue(OtaStatus.CHECK_NEW_VERSION);
            localOtaStatusMutableLiveData.postValue(null);
            initData();
        }

        @Override
        public void onFailed(String msg) {
            initData(OtaStatus.IDLE);
            if (iOtaOperationFailedInter != null) {
                iOtaOperationFailedInter.checkFailed(msg);
            }
        }
    };

    IDownloadInter iDownloadInter = new IDownloadInter() {
        @Override
        public void onStart() {
            otaStatusMutableLiveData.postValue(OtaStatus.DOWNLOADING);
            Trace.d(TAG, "download start ");
        }

        @Override
        public void onSuccess() {
            otaStatusMutableLiveData.postValue(OtaStatus.DOWNLOAD_FINISHED);
            Trace.d(TAG, "download success ");
        }

        @Override
        public void onDownloadProgress(int progress) {
            otaStatusMutableLiveData.postValue(OtaStatus.DOWNLOADING);
            localOtaStatusMutableLiveData.postValue(null);
            Trace.d(TAG, "onDownloadProgress() " + progress);
            dlProgress.postValue(progress);
            progressObservable.postValue(progress + "%");
        }

        @Override
        public void onFailed(int code) {
            initData();
            if (iOtaOperationFailedInter != null) {
                iOtaOperationFailedInter.downloadFailed(Constant.getDlTipByErrorCode(code));
            }
            Trace.d(TAG, "download failed, code: " + code + " Error message: " + Error.getErrorMessage(code));
        }

        @Override
        public void onCancel() {
            otaStatusMutableLiveData.postValue(OtaStatus.DOWNLOAD_PAUSE);
            Trace.d(TAG, "download pause");
        }
    };

    private IRebootUpgradeCallBack iRebootUpgradeCallBack = new IRebootUpgradeCallBack() {
        @Override
        public boolean rebootConditionPrepare() {
            SPFTool.putBoolean(SP_IS_LOCAL_UPDATE, false);
            return true;
        }

        @Override
        public void onUpgrading(float v) {
            otaStatusMutableLiveData.postValue(OtaStatus.UPGRADING);
            dlProgress.postValue((int) v);
            Trace.d(TAG, "onUpgrading: " + v);
        }

        @Override
        public void onSuccess() {
            otaStatusMutableLiveData.postValue(OtaStatus.UPGRADE_SUCCESS);
            handler.post(() -> {
                MainActivity mainActivity = ActivityCollector.getActivity(MainActivity.class);
                if (mainActivity != null) {
                    mainActivity.createChooseAbupdateDialog();
                }
            });
        }

        @Override
        public void onError(int i) {
            //避免出现升级失败状态 -> 升级失败状态导致的界面问题
            otaStatusMutableLiveData.postValue(OtaStatus.UPGRADING);
            initData();
            if (iOtaOperationFailedInter != null) {
                handler.post(() -> iOtaOperationFailedInter.updateFailed(Constant.getUpdateTipByErrorCode(i)));
            }

            Trace.d(TAG, "upgrade failed, code: " + i + " Error message: " + Constant.getUpdateTipByErrorCode(i));
        }
    };

    private IRebootUpgradeCallBack iLocalRebootUpgradeCallBack = new IRebootUpgradeCallBack() {
        @Override
        public boolean rebootConditionPrepare() {
            return true;
        }

        @Override
        public void onUpgrading(float v) {
            otaStatusMutableLiveData.postValue(OtaStatus.UPGRADING);
            localOtaStatusMutableLiveData.postValue(LocalOtaStatus.UPGRADING);
            dlProgress.postValue((int) v);
            Trace.d(TAG, "onUpgrading: " + v);
        }

        @Override
        public void onSuccess() {
            otaStatusMutableLiveData.postValue(OtaStatus.UPGRADE_SUCCESS);
            localOtaStatusMutableLiveData.postValue(LocalOtaStatus.UPGRADE_SUCCESS);
            Trace.d(TAG, "onSuccess ");
            MainActivity mainActivity = ActivityCollector.getActivity(MainActivity.class);
            handler.post(() -> {
                if (mainActivity != null) {
                    mainActivity.createChooseAbupdateDialog();
                }
            });
        }

        @Override
        public void onError(int i) {
            otaStatusMutableLiveData.postValue(OtaStatus.UPGRADING);
            initData();
            if (iOtaOperationFailedInter != null) {
                handler.post(() -> iOtaOperationFailedInter.updateFailed(Constant.getUpdateTipByErrorCode(i)));
            }
            Trace.d(TAG, "upgrade failed, code: " + i + " Error message: " + Constant.getUpdateTipByErrorCode(i));
        }
    };

    private void registerListener() {
        mModel.registerDownloadListener(iDownloadInter);
        if (SPFTool.getBoolean(SP_IS_LOCAL_UPDATE, false)) {
            Trace.d(TAG, "register local reboot Listener");
            mModel.registerUpgradeListener(iLocalRebootUpgradeCallBack);
        } else {
            Trace.d(TAG, "register Reboot Listener");
            mModel.registerUpgradeListener(iRebootUpgradeCallBack);
        }
    }

    private void unRegisterListener() {
        mModel.unRegisterUpgradeListener();
        mModel.unRegisterDownloadListener();
        mModel.unRegisterCheckListener();
        iOtaOperationFailedInter = null;
    }

    @Override
    public void onDestroy() {
        Trace.d(TAG, "onDestroy");
        if (null != fotaInject) {
            fotaInject.unInject();
        }
        unRegisterListener();
        super.onDestroy();
    }

    @Override
    public void onResume() {
        if (FotaInitTask.isCompleted()) {
            registerListener();
        }
        super.onResume();
    }

    public void resetStatus() {
        OtaStatusMgr otaStatusMgr = OtaStatusMgr.getInstance();
        if (otaStatusMgr.isDownloading()) {
            RxTime.newInstance()
                    .setMinTime(1000)
                    .setICondition(() -> mModel.downloadCancel())
                    .setPeriod(200)
                    .enqueue(true, new RxTime.IEnqueueListener() {
                        @Override
                        public void onComplete() {
                            try {
                                Thread.sleep(1000);
                                otaStatusMgr.refreshOtaStatus(OtaStatus.IDLE);
                                initData();
                                CleanUtils.cleanAll();
                                Trace.d(TAG, "Delete cache file");
                                Toast.makeText(App.sCx, App.sCx.getResources().getString(R.string.clean_cache_tips), Toast.LENGTH_SHORT).show();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }

                        @Override
                        public void onTimeOut() {

                        }
                    });
        } else {
            otaStatusMgr.refreshOtaStatus(OtaStatus.IDLE);
            initData();
            CleanUtils.cleanAll();
            Trace.d(TAG, "Delete cache file");
            Toast.makeText(App.sCx, App.sCx.getResources().getString(R.string.clean_cache_tips), Toast.LENGTH_SHORT).show();
        }
    }
}
